package com.ng8866.gateway.filter;


import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import com.ng8866.api.reactive.user.GameMemberAuthClient;
import com.ng8866.common.utils.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;


@Slf4j
@Component
@ConfigurationProperties(prefix = "authorization")
public class AuthorizationFilter implements GlobalFilter, Ordered {

    public List<String> adminIgnorePaths = new ArrayList<>();

    public List<String> adminPaths = new ArrayList<>();

    public List<String> userPaths = new ArrayList<>();


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().toString();
        String serverType = getServerType(request, path);
        exchange.mutate().request(request.mutate().headers(httpHeaders -> {
            httpHeaders.add("ServerType", serverType);
        }).build()).build();
        // 地址校验
        if (checkIsInList(path, adminPaths)) {
            if (!checkIsInList(path, adminIgnorePaths)) {
                log.info("==> 进入管理统一权限鉴定处理, path:{}", path);
                // 拿到 token
                String token = request.getHeaders().getFirst("Token");
                if (null == token || token.isEmpty()) {
                    return tokenError(exchange, 401, "缺少验证信息");
                }
                // 验证token
                if (TokenUtil.checkAdminToken(token)) {
                    return chain.filter(exchange);
                } else {
                    return tokenError(exchange, 401, "验证失败");
                }
            }
        } else if (checkIsInList(path, userPaths)) {
            log.info("==> 进入用户统一权限鉴定处理, path:{}", path);
            String token = request.getHeaders().getFirst("Token");
            String userid = request.getHeaders().getFirst("Userid");
            if (null == token || token.isEmpty() || null == userid || userid.isEmpty()) {
                return tokenError(exchange, 401, "缺少验证信息");
            }
            GameMemberAuthClient gameMemberAuthClient = SpringUtil.getBean(GameMemberAuthClient.class);
            return gameMemberAuthClient.checkMemberInfo(token, userid, serverType).flatMap(ret -> {
                // 检查token有效性
                if (ret == null) {
                    return this.tokenError(exchange, 401, "验证失败");
                } else if (200 != ret.getInt("code")) {
                    return this.tokenError(exchange, ret.getInt("code"), ret.getStr("msg"));
                }
                return chain.filter(exchange);
            });
        }
        return chain.filter(exchange);
    }

    /**
     * 设置服务类型
     */
    private String getServerType(ServerHttpRequest request, String path) {
        String agent = request.getHeaders().getFirst("user-agent");
        if(path.contains("/h5/") && StrUtil.isNotEmpty(agent) && agent.contains("uni-app")){
            return "uni-app";
        }else if(path.contains("/h5/")){
            return "h5";
        }else {
            return "pc";
        }
    }

    private Mono<Void> tokenError(ServerWebExchange exchange, Integer code, String msg) {
        ServerHttpResponse response = exchange.getResponse();
        JSONObject message = new JSONObject();
        message.set("code", code);
        message.set("msg", msg);
        message.set("data", ListUtil.empty());
        byte[] bits = message.toString().getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bits);
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        //指定编码，否则在浏览器中会中文乱码
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(buffer));
    }

    /**
     * 指定全局过滤器执行的顺序
     *
     * @return
     */
    @Override
    public int getOrder() {
        // 指定过滤器执行的时机
        return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 100;
    }

    /**
     * 校验
     *
     * @param str
     * @param list
     * @return
     */
    private Boolean checkIsInList(String str, List<String> list) {
        if (str == null || list.size() < 1) {
            return false;
        }
        for (String name : list) {
            if (str.contains(name)) {
                return true;
            }
        }
        return false;
    }

    public List<String> getAdminIgnorePaths() {
        return adminIgnorePaths;
    }

    public void setAdminIgnorePaths(List<String> adminIgnorePaths) {
        this.adminIgnorePaths = adminIgnorePaths;
    }

    public List<String> getAdminPaths() {
        return adminPaths;
    }

    public void setAdminPaths(List<String> adminPaths) {
        this.adminPaths = adminPaths;
    }

    public List<String> getUserPaths() {
        return userPaths;
    }

    public void setUserPaths(List<String> userPaths) {
        this.userPaths = userPaths;
    }

}